using Cysharp.Threading.Tasks;
using DG.Tweening;
using IQIGame.Onigao.Framework;
using UnityEngine;

namespace IQIGame.Onigao.GamePlay
{
    public class InteractStateJump : InteractStateBase
    {
        public InteractStateJump(LevelPlayRegionController regionCtrl) : base(regionCtrl)
        {
        }

        public override LevelInteractState stateId => LevelInteractState.Jump;

        private LevelInteractState _prevStateId;

        public override void OnInit()
        {
        }

        public override bool IsNextStateValid(LevelInteractState nextId)
        {
            return true;
        }

        /// <summary>
        /// 开始跳跃
        /// </summary>
        public async UniTaskVoid StartJump(InteractJump jumpData)
        {
            LogGame.Log("Start Jump");

            var character = this.regionCtrl.entityCtrl.GetMainCharacter();

            //旋转
            var rotation = GameMathUtil.IntEuler2Quaternion(jumpData.ledgeEntity.dirEuler);

            //落点
            var position = character.GetRecastVec3Pos();
            var destPosition = LevelMathUtil.MoveInDirection(position, rotation,
                GameMathUtil.LogicValue2Float(jumpData.jumpDistance));
            //空中点
            var airPosition = destPosition;
            //加上高度差的最终点
            var logicHeight = GameMathUtil.LogicValue2Float(jumpData.jumpHeight);
            destPosition.y += logicHeight;
            //通过recast计算实际落点
            this.regionCtrl.navigationCtrl.FindNearestPoint(destPosition, out var navMeshPos);
            if (GameScenePlayUtil.TryGroundRaycast(navMeshPos.x, navMeshPos.y, navMeshPos.z, out var hit))
            {
                navMeshPos = new Vector3(navMeshPos.x, hit.point.y, navMeshPos.z);
            }

            //旋转到正常向
            await character.transform.DORotateQuaternionSpeedBase(rotation, ViewEntityConst.EntityRotationSpeed)
                .SetLink(character.gameObject).AwaitForComplete();

            //使用跳跃配置
            JumpConfigAsset jumpConfig = this.regionCtrl.entityViewCtrl.jumpConfig;
            if (jumpConfig == null)
            {
                LogGame.LogWarning($"JumpConfigAsset is null");
                character.transform.position = navMeshPos;
                character.UpdatePosToData(navMeshPos);

                //离开到之前的状态
                ChangeState(this._prevStateId);
                return;
            }

            airPosition.y += jumpConfig.jumpHeightOffset;
            float fallTime = (Mathf.Abs(logicHeight) + jumpConfig.jumpHeightOffset) / jumpConfig.jumpFallSpeed;
            var siwtchEndTime = jumpConfig.jumpStartCrossTime + jumpConfig.jumpToHightTime +
                                fallTime * jumpConfig.switchEndProgress;
            var extraEndTime = Mathf.Max(jumpConfig.jumpEndTime - fallTime * (1 - jumpConfig.switchEndProgress), 0f);


            //播放起跳动画
            //character.GetAnimationComponent().PlayJumpStart(jumpConfig.jumpStartCrossTime);
            character.GetAnimationComponent().PlayJumpStartTrigger();

            //跳跃序列
            await DOTween.Sequence().SetLink(character.gameObject)
                .SetTarget(character.transform)
                .AppendInterval(jumpConfig.jumpStartCrossTime)
                .Append(character.transform.DOMove(airPosition, jumpConfig.jumpToHightTime)
                    .SetEase(jumpConfig.jumpToHeightCurve))
                .Append(character.transform.DOMove(navMeshPos, fallTime).SetEase(jumpConfig.jumpFallCurve))
                .InsertCallback(siwtchEndTime, () => { character.GetAnimationComponent().TriggerJumpEnd(); })
                .AppendInterval(extraEndTime)
                .AwaitForComplete();
            character.UpdatePosToData(navMeshPos);

            LogGame.Log("End Jump");

            //离开到之前的状态
            ChangeState(this._prevStateId);
        }

        public override void OnEnter(LevelInteractState prevStateId)
        {
            this._prevStateId = prevStateId;

            this.fsm.TryGetState<InteractStateOperational>(LevelInteractState.Operational, out var stateOperational);
            StartJump(stateOperational.interactJump).Forget();
        }

        public override void OnExit()
        {
            var character = this.regionCtrl.entityCtrl.GetMainCharacter();
            character.transform.DOKill();
        }

        public override void Dispose()
        {
        }
    }
}